/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or (at
 * your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 * 02110-1301, USA.
 * */

// AmzServer - Tototoy's server model.
// Author: tonyjobmails@gmail.com (tonyhack).
//
// Define class RingQueueSingleModelBoundless.
//
// RingQueueSingleModelBoundless is an implement of RingQueueInterface. This
// implement is a version of "double-thread safe". That is to say, there are only 2
// threads in this producer/consumer model, the producer one only read from the
// queue, and the consumer one only write to it, RingQueueSingleModelBoundless
// is thread-safe in this condition. Because of using lock-free, This RingQueueSin-
// gleModelBoundless performances a high efficiency in this model.
// This RingQueueSingleModelBoundless is boundless, it uses ByteBufferDynamic
// as it's extended queue. The extended queue is a extendable buffer, it can reduce
// the times of memory allocation, so it makes RingQueueSingleModelBoundless
// more efficientive.
// RingQueueSingleModelBoundless also supports blocking pattern, that is to say,
// when the consumer read from the queue, if the queue is empty, the consumer
// will enter into the waiting state, it will be blocked until the producer thread writes
// any new data into the queue. however, RingQueueSingleModelBoundless also
// supports non-blocking pattern.
// Attention, the producer thread does not permit to quit until the extended queue
// is empty. the poducer thread can invokes Shift2Ring(), if the return value is true,
// it can quit immediately, and if not, the producer thread should invoke Shift2Ring()
// after serval milliseconds or longer, this invoking frequency depend on the speed
// of consumer thread.
//

#ifndef __RING__QUEUE__SINGLE__MODEL__BOUNDLESS__H
#define __RING__QUEUE__SINGLE__MODEL__BOUNDLESS__H

#include "ring_queue_define.h"
#include "ring_queue_blocking_interface.h"
#include "byte_buffer_dynamic.h"
#include "byte_buffer_static.h"
#include "buffer_define.h"
#include "condition_variable.h"

namespace amz {

namespace ring_queue_define {

// This default value will be the size of dynamic queue's memory append.
const uint32 kDefaultBufferSingleUnitSize = sizeof(RingQueueElement) + 1024 * 32;

}  // namespace ring_queue_define

// This class use "ByteBufferDynamic" as its dynamic queue and use
// "ByteBufferStaticMalloc" as its ring queue.
class RingQueueSingleModelBoundless : public RingQueueBlockingInterface {
  // typedef
  typedef ByteBufferStaticMalloc StaticRingQueue;
  typedef ByteBufferDynamic DynamicQueue;
  
 public:
  // In single thread, argument blocking must give "false".
  RingQueueSingleModelBoundless(uint32 ring_size = ring_queue_define::kDefaultRingQueueSize,
         uint32 dynamic_queue_extend_size = ring_queue_define::kDefaultBufferSingleUnitSize,
         bool blocking = false);
  virtual ~RingQueueSingleModelBoundless();

  virtual int GetType() { return ring_queue_define::RingQueueType_SingleBoundless; }

  // Use only for producer thread.
  virtual int Add(const char *element, uint32 size);

  // Use only for consumer thread.
  virtual int Remove(char *element, uint32 max_size);

  // Use only for consumer thread.
  virtual bool Flush();

  // When producer finish producing, this should be invoked
  virtual void ProduceCompletely();

  // Check all the producers produce completely.
  virtual bool CheckAllProducersComplete();

  // Debug print member.
  void LogPrint();

 private:
  // Shift element into ring queue.
  // Use only for producer thread.
  bool Shift2Ring();
  
  // Try to add data element to ring_ without shifting to ring_.
  bool TryAdd(const char *element, uint32 size);
  
  // The ring queue.
  StaticRingQueue ring_;
  // size of ring queue.
  uint32 ring_size_;
  // The position to write the next data element.
  volatile uint32 write_pointer_;
  // The position to read from the ring queue.
  volatile uint32 read_pointer_;
  
  // Dynamic queue.
  DynamicQueue dynamic_queue_;

  // Blocking pattern.
  bool blocking_;

  // Condition variable.
  ConditionVariable condition_not_empty_;
  // mutex
  mutable Mutex mutex_;

  bool produce_completely_;
};

}  // namespace amz

#endif  // __RING__QUEUE__SINGLE__MODEL__BOUNDLESS__H

